<!DOCTYPE html>
<html>
  <head>
    <meta content="text/html; charset=UTF-8" http-equiv="content-type">
    <title>ch03-03</title>
    <link href="css/style.css" rel="stylesheet" type="text/css">
    <link rel="stylesheet" href="thumbnailviewer.css" type="text/css">
    <script src="thumbnailviewer.js" type="text/javascript">

/***********************************************
* Image Thumbnail Viewer Script- © Dynamic Drive (www.dynamicdrive.com)
* This notice must stay intact for legal use.
* Visit http://www.dynamicdrive.com/ for full source code
***********************************************/

</script> </head>
  <body>
    <div class="os1">3.3 QAudioRecorder录音到文件 </div>
    <br>
    本节介绍利用 QAudioRecorder 进行傻瓜式的录音，该类可以自动采集音频数据并保存为 wav 格式文件。QAudioRecorder 还可以与
    QAudioProbe 音频探针配合使用，音频探针可以从 QAudioRecorder 实时捕获音频数据，实时音频数据以 QAudioBuffer
    对象提供给程序，这些实时音频数据可以用于网络发送或进行其他处理。<br>
    <br>
    本节分为三部分，第一小节介绍 QAudioRecorder 录音类，第二小节介绍 QAudioProbe 音频探针和 QAudioBuffer
    音频缓存类， 最后小节介绍 QAudioRecorder 录音示例，在录音的同时获取实时音频数据发送到网络。 <br>
    <br>
    <div class="os2">3.3.1 QAudioRecorder录音类 </div>
    <br>
    QAudioRecorder 是高级别的音频录制类，它的基类是 QMediaRecorder。QMediaRecorder
    包含通用的录音或录像功能函数，其派生类 QAudioRecorder 是对录音的定制处理，QAudioRecorder
    支持简单的音频编码和文件封装。下面我们介绍 QAudioRecorder 常用的功能函数。<br>
    （1）构造函数<br>
    <div class="code">QAudioRecorder(QObject * parent = 0)<br>
      ~QAudioRecorder() //析构函数</div>
    QAudioRecorder 构造函数除了父对象指针就没有别的参数了，因为 QAudioRecorder
    将音频设备和音频格式封装在内部，将底层设备和参数尽量隐藏起来，对用户而言，参数越少，该类就越简单易用。<br>
    <br>
    （2）采集设备和音量设置<br>
    QAudioRecorder 不能直接设置音频采集设备对象，而是使用设备名称字符串代表该设备。QAudioRecorder 类只有获取和设置设备字符串的
    函数：<br>
    <div class="code">void setAudioInput(const QString &amp; name)&nbsp; //设置音频采
      集设备名称，这个是槽函数<br>
      QString audioInput() const&nbsp; //获取使用的音频采集设备名称</div>
    QAudioRecorder 类将底层的 QAudioInput、QAudioFormat、QAudioDeviceInfo
    都隐藏起来了，只能获取或者设置设备名称字符串。<br>
    QAudioRecorder 可以用成员函数查询支持的多个采集设备名称的字符串：<br>
    <div class="code">QStringList audioInputs() const&nbsp; //获取支持的音频采集设备名称列表<br>
      QString defaultAudioInput() const //获取默认的一个音频采集设备名称</div>
    另外还可以根据设备名称查询详细的设备描述字符串：<br>
    <div class="code">QString audioInputDescription(const QString &amp; name)
      const</div>
    该函数根据参数 name 指定的音频采集设备，查询该设备详细的描述字符串。QAudioRecorder 提供的设备查询和设置函数都是基于人类可读的字符
    串，而不关心底层的设备对象和格式对象，其编程接口更加傻瓜化。<br>
    <br>
    QAudioRecorder 也是可以设置音量的，通过基类的功能函数：<br>
    <div class="code">void setVolume(qreal volume) //设置音量 1.0 代表100%<br>
      qreal volume() const&nbsp; //获取音量</div>
    <br>
    （3）音频编码器设置<br>
    QAudioRecorder 不能直接设置音频采集格式 QAudioFormat，只能设置音频编码器对象 QAudioEncoderSettings：<br>
    <div class="code">void setAudioSettings(const QAudioEncoderSettings &amp;
      settings) //设置音频编码器<br>
      QAudioEncoderSettings audioSettings() const&nbsp; //获取音频编码器设置</div>
    QAudioEncoderSettings
    专门描述音频编码器的参数。音频编码器对于输入数据，一般都有支持的采样率、位宽、通道数等等参数范围；对于输出数据，压缩后的数据速率也是有一定范围。所以
    QAudioEncoderSettings 有些函数会受到编码器的影响，如果编码器不支持，那么再怎么设置参数也没用。我们下面列举
    QAudioEncoderSettings 几个常用的函数：<br>
    <br>
    <table class="tabel">
      <tbody>
        <tr class="d1">
          <td style="width: 280px;" align="center"><b> QAudioEncoderSettings
              参数设置函数</b></td>
          <td style="width: 120px;" align="center"><b>获取函数</b></td>
          <td align="center"><b> 描述</b></td>
        </tr>
        <tr>
          <td>setCodec(const QString &amp; codec)</td>
          <td> QString codec()</td>
          <td style="height: 45px;"> 编码器名称，一般设为"audio/pcm"，这个可以指硬件设备支持的编码格式，也可以指
            音频压缩编码器的名称，比如 "audio/mpeg"。 <br>
          </td>
        </tr>
        <tr class="d1">
          <td>setChannelCount(int channels)</td>
          <td style="height: 17px;"> int channelCount()</td>
          <td> 采样通道数，一般是 1 或 2。</td>
        </tr>
        <tr>
          <td>setSampleRate(int rate)</td>
          <td> int sampleRate()</td>
          <td style="height: 45px;"> 采样频率，建议用的数值为 8000, 44100,
            48000。这个设置值不一定有用，可能被其他函数修改。</td>
        </tr>
        <tr class="d1">
          <td>setEncodingMode(QMultimedia::EncodingMode mode)</td>
          <td> QMultimedia::EncodingMode&nbsp;&nbsp;&nbsp; encodingMode()</td>
          <td> 设置编码器模式，有四种模式：<br>
            ConstantQualityEncoding、ConstantBitRateEncoding、
            AverageBitRateEncoding、<br>
            TwoPassEncoding</td>
        </tr>
        <tr>
          <td>setQuality(QMultimedia::EncodingQuality quality)</td>
          <td> QMultimedia::EncodingQuality&nbsp;&nbsp; &nbsp;quality() </td>
          <td> 编码质量，只对ConstantQualityEncoding模式的编码器有用。</td>
        </tr>
        <tr class="d1">
          <td>setBitRate(int rate)</td>
          <td> int bitRate() </td>
          <td> 压缩编码后的输出比特率，设置的数值不一定有用，与编码器性能有关。</td>
        </tr>
      </tbody>
    </table>
    <br>
    我们对 QAudioEncoderSettings 展开讲解一下：<br>
    ① 音频编码器<br>
    这里的音频编码器 codec() 可以指音频采集硬件直接支持的 "audio/pcm"，这样代表原始的裸 PCM 数据不进行压缩编码，直接输出原始
    PCM 数据；codec() 也可以指将原始 PCM 数据进行压缩的音频编码器，比如 "audio/mpeg" 是指将原始音频数据按照 mpeg
    音频编码压缩后输出。Linux 系统中 Qt 支持的音频编码器种类比较多，但是 Windows 系统支持的音频编码器可能很少，查询
    QAudioRecorder 支持的音频编码器使用基类的函数：<br>
    <div class="code">QStringList QMediaRecorder::​supportedAudioCodecs() const</div>
    比较坑爹的是，作者 Windows 系统的 Qt 5.4 版本仅支持 "audio/pcm" 一种编码，还是声卡采集的原始数据。<br>
    ② 采样通道数<br>
    采样通道数没什么悬念，一般就是 1 或者 2 。<br>
    ③ 采样频率<br>
    QAudioRecorder 基类也提供了查询采样频率支持情况的函数：<br>
    <div class="code">QList&lt;int&gt;
      QMediaRecorder::​supportedAudioSampleRates(const QAudioEncoderSettings
      &amp; settings = QAudioEncoderSettings(), bool * continuous = 0) </div>
    该函数的参数都带默认值，可以不设置参数，获取音频采集设备默认支持的采样频率。<br>
    如果参数 settings 指定了某个编码器名称，那么返回指定编码器支持的输入数据采样频率。<br>
    第二个参数是返回值指针，continuous 指向的数值如果为 true，说明编码器支持最小值到最大值之间任意的采样频率数值，一般该值都是
    false，仅 支持非连续的采样频率。<br>
    <br>
    ④ 编码模式和编码质量<br>
    因为作者开发环境只支持 "audio/pcm" 一种编码 ，所以其他模式无法测试，只有 ConstantQualityEncoding
    模式的采样参数可以确定。在 ConstantQualityEncoding 模式下，录音时总是设置 "audio/pcm" 编码，作者专门研究了 Qt
    的源代码，在下面文件里找到了各种录音质量对应的参数设置：<br>
C:\Qt\Qt5.4.0\5.4\Src\qtmultimedia\src\plugins\audiocapture\audioencodercontrol.cpp<br>
    具体的设置函数为：<br>
    void AudioEncoderControl::setAudioSettings(const QAudioEncoderSettings
    &amp;settings)<br>
    <br>
    Qt 源代码中 ConstantQualityEncoding 模式下五种录音编码质量的参数设置如下表所示：<br>
    <br>
    <table class="tabel">
      <tbody>
        <tr class="d1">
          <td style="width: 200px;" align="center"><b>录音编码质量</b></td>
          <td style="width: 100px;" align="center"><b>采样频率</b></td>
          <td style="width: 100px;" align="center"><b>采样位宽</b></td>
          <td style="width: 200px;" align="center"><b>采样点数值类型</b></td>
        </tr>
        <tr>
          <td>QMultimedia::VeryLowQuality（0）</td>
          <td> 8000</td>
          <td> 8</td>
          <td> QAudioFormat::UnSignedInt </td>
        </tr>
        <tr class="d1">
          <td style="height: 15px;">QMultimedia::LowQuality（1）</td>
          <td> 22050 </td>
          <td> 8 </td>
          <td> QAudioFormat::UnSignedInt </td>
        </tr>
        <tr>
          <td>QMultimedia::NormalQuality（2，默认值）</td>
          <td> 44100 </td>
          <td> 16 </td>
          <td> QAudioFormat::SignedInt </td>
        </tr>
        <tr class="d1">
          <td>QMultimedia::HighQuality（3）</td>
          <td> 48000 </td>
          <td> 16 </td>
          <td> QAudioFormat::SignedInt </td>
        </tr>
        <tr>
          <td>QMultimedia::VeryHighQuality（4）</td>
          <td> 96000 </td>
          <td> 16</td>
          <td> QAudioFormat::SignedInt </td>
        </tr>
      </tbody>
    </table>
    <br>
    ConstantQualityEncoding 模式下的编码器都是声卡直接支持的 "audio/pcm" 编码，采样数值的字节序是系统默认值，通道数则由
    setChannelCount(int channels) 函数指定。其他模式下的情况不确定。<br>
    QAudioRecorder 和 QAudioEncoderSettings 隐藏了音频采集设备、音频格式等等底层细节，但是坑爹的影响
    是，QAudioEncoderSettings 其他几种模式情况下的音频格式、编码器参数不确定。<br>
    <br>
    ⑤ 压缩编码后的比特率<br>
    setBitRate(int rate) 也是非常不靠谱的函数，因为音频采集参数和编码器的参数都会影响到输出的比特率，情况复杂，设置的数值很可能没用。<br>
    <br>
    （4）文件容器设置<br>
    QAudioRecorder 支持将音频数据存到 wav 格式文件，这是它的一个优点，带格式的音频文件被称为文件容器，设置文件容器的函数如下：<br>
    <div class="code">void setContainerFormat(const QString &amp; container)
      //设置文件容器格式<br>
      QString containerFormat() const //获取文件容器格式</div>
    文件容器格式仅仅是指格式名称，不是要保存的文件路径和文件名。查询支持的文件容器格式，使用下面函数：<br>
    <div class="code">QStringList supportedContainers() const</div>
    &nbsp;wav 文件对应的字符串是 "audio/x-wav"，无封装的裸数据文件对应 "audio/x-raw" 。<br>
    <br>
    保存录音文件的路径是通过 URL 路径设置的：<br>
    <div class="code">bool setOutputLocation(const QUrl &amp; location)
      //设置文件输出路径<br>
      QUrl outputLocation() const&nbsp; //只有在录音进行时，才能获取输出路径</div>
    本地文件名转为 URL 举例如下：<br>
    <div class="code">&nbsp;&nbsp;&nbsp; QAudioRecorder recorder;<br>
      &nbsp;&nbsp;&nbsp; recorder.setContainerFormat( "audio/x-wav" );<br>
      &nbsp;&nbsp;&nbsp; QUrl fileURL = QUrl::fromLocalFile( "E:/1.wav" );<br>
      &nbsp;&nbsp;&nbsp; bool bret = recorder.setOutputLocation( fileURL );<br>
      &nbsp;&nbsp;&nbsp; qDebug()&lt;&lt;bret;<br>
      &nbsp;&nbsp;&nbsp; recorder.record();<br>
      &nbsp;&nbsp;&nbsp; qDebug()&lt;&lt;recorder.outputLocation();</div>
    设置文件URL成功后，返回值 bret 为 true，录音之前无法获取输出的路径 URL，只有在录音开始后，才能获取保存的录音文件 URL，比如为
    QUrl( "file:///E:/1.wav" ) 。<br>
    <br>
    （5）开始和停止录音<br>
    QAudioRecorder 和基类 QMediaRecorder 没有 start 之类的函数，而是直接用下面录音函数：<br>
    <div class="code">void record() //开始录音</div>
    停止录音函数如下：<br>
    <div class="code">void stop() //停止录音</div>
    虽然录音类有暂停录音的函数 pause() ，但该暂停函数依赖系统平台实现，有可能是无效的。如果调用暂停函数暂停了录音，可以调用 record()
    继续录 音。<br>
    <br>
    （6）状态查询函数<br>
    QAudioRecorder 和基类 QMediaRecorder 的状态表述有点复杂，区分用户操作同步状态和异步状态。<br>
    与用户的 record()、pause()、stop() 操作函数同步的状态查询函数如下：<br>
    <div class="code">State&nbsp; state() const //与用户操作同步的状态</div>
    QMediaRecorder::​State 枚举常量如下表所示：<br>
    <br>
    <table class="tabel">
      <tbody>
        <tr class="d1">
          <td style="width: 320px;" align="center"><b>QMediaRecorder::​ State
              枚举常量</b></td>
          <td style="width: 100px;" align="center"><b>数值</b></td>
          <td align="center"><b> 描述</b></td>
        </tr>
        <tr>
          <td>QMediaRecorder::StoppedState</td>
          <td> 0 </td>
          <td> 停止状态。 </td>
        </tr>
        <tr class="d1">
          <td>QMediaRecorder::RecordingState</td>
          <td> 1</td>
          <td> 请求录制状态。 </td>
        </tr>
        <tr>
          <td>QMediaRecorder::PausedState</td>
          <td> 2 </td>
          <td> 暂停状态。 </td>
        </tr>
      </tbody>
    </table>
    <br>
    用户操作同步状态 state() 是面向用户操作的，只说明用户进行了何种操作，并不反映录音对象实际正在进行什么处理。<br>
    用户操作异步状态 status()才是反映录音对象实际进行的处理操作：<br>
    <div class="code">Status status() const&nbsp; //与用户操作异步的状态，反映录音对象实际进行的处理操作</div>
    录音对象的具体操作可以细化为下表所示的用户操作异步状态：<br>
    <br>
    <table class="tabel">
      <tbody>
        <tr class="d1">
          <td style="width: 320px;" align="center"><b>QMediaRecorder::​ Status
              枚举常量</b></td>
          <td style="width: 100px;" align="center"><b>数值</b></td>
          <td align="center"><b> 描述</b></td>
        </tr>
        <tr>
          <td>QMediaRecorder::UnavailableStatus</td>
          <td> 0 </td>
          <td> 不可用状态，录制对象不可用或连接的媒体对象不支持录制。 </td>
        </tr>
        <tr class="d1">
          <td>QMediaRecorder::UnloadedStatus</td>
          <td> 1</td>
          <td> 录制对象可用，但还没加载。 </td>
        </tr>
        <tr>
          <td>QMediaRecorder::LoadingStatus</td>
          <td> 2 </td>
          <td> 录制对象正在加载。 </td>
        </tr>
        <tr class="d1">
          <td>QMediaRecorder::LoadedStatus</td>
          <td> 3 </td>
          <td> 录制对象已经初始化，录制准备就绪。 </td>
        </tr>
        <tr>
          <td style="height: 15px;">QMediaRecorder::StartingStatus</td>
          <td> 4 </td>
          <td> 录制操作正在请求中，但还没正式开始。</td>
        </tr>
        <tr class="d1">
          <td>QMediaRecorder::RecordingStatus</td>
          <td> 5</td>
          <td> 录制操作正在进行。</td>
        </tr>
        <tr>
          <td>QMediaRecorder::PausedStatus</td>
          <td> 6</td>
          <td> 录制操作被暂停了。</td>
        </tr>
        <tr class="d1">
          <td>QMediaRecorder::FinalizingStatus</td>
          <td> 7</td>
          <td> 录制操作已经停止了，媒体正在执行结束操作。</td>
        </tr>
      </tbody>
    </table>
    <br>
    异步状态 status() 反映录制对象真实的工作流程状态；而同步状态 state() 仅体现用户操作。<br>
    <br>
    如果录制过程出错，那么可以查询出错的代号和错误信息字符串：<br>
    <div class="code">Error error() const&nbsp; //获取错误代号<br>
      QString errorString() const //获取错误信息字符串</div>
    错误代号具体如下表所示：<br>
    <br>
    <table class="tabel">
      <tbody>
        <tr class="d1">
          <td style="width: 320px;" align="center"><b style="">QMediaRecorder::
              ​ Error 枚举常量</b></td>
          <td style="width: 100px;" align="center"><b>数值</b></td>
          <td align="center"><b> 描述</b></td>
        </tr>
        <tr>
          <td>QMediaRecorder::NoError</td>
          <td> 0 </td>
          <td> 没有出错。 </td>
        </tr>
        <tr class="d1">
          <td>QMediaRecorder::ResourceError</td>
          <td> 1</td>
          <td> 设备没有准备好或不可用。 </td>
        </tr>
        <tr>
          <td>QMediaRecorder::FormatError</td>
          <td> 2 </td>
          <td> 当前设定的格式不支持。 </td>
        </tr>
        <tr class="d1">
          <td>QMediaRecorder::OutOfSpaceError</td>
          <td> 3 </td>
          <td> 设备没有可用空间。 </td>
        </tr>
      </tbody>
    </table>
    <br>
    查询录制的时间长度，使用下面函数：<br>
    <div class="code">qint64 duration() const</div>
    时长单位是毫秒（milliseconds）。<br>
    <br>
    （7）信号<br>
    QAudioRecorder 自身带有 2 个信号：<br>
    <div class="code">void audioInputChanged(const QString &amp; name) //音频输入设备变
      化，参数是新设备名<br>
      void volumeChanged(qreal volume) //音量变化</div>
    QAudioRecorder 其他信号继承自基类 QMediaRecorder，这里只列举几个常用的，不是全部：<br>
    <div class="code">void&nbsp; stateChanged(QMediaRecorder::State state)
      //同步状态变化，与用户操作相关<br>
      void&nbsp; statusChanged(QMediaRecorder::Status status)
      //异步状态变化，与录制对象实际工作状态相关<br>
      void&nbsp; error(QMediaRecorder::Error error) //错误代号变化<br>
      void&nbsp; durationChanged(qint64 duration)&nbsp; //录制时长变化，时间单位毫秒</div>
    <br>
    Qt 帮助文档里面有关于 QAudioRecorder 的示例 audiorecorder，文件路径为：<br>
    C:\Qt\Qt5.4.0\Examples\Qt-5.4\multimedia\audiorecorder<br>
    运行该示例测试可以发现 QAudioEncoderSettings 的设置函数是很不靠谱的，先测试固定质量录音模式：<br>
    <center> <img src="images/ch03/ch03-03-01.png" alt="set1"> <img src="images/ch03/ch03-03-02.png"
        alt="rec1"> </center>
    在固定质量模式下，设置采样频率 8000 Hz，最高质量录音，然后开始录音。录音后的文件使用 MediaInfo
    工具查看音频文件参数，与示例程序设置的参数作对比。<br>
    在实际得到的录制文件中，采样频率是 96000 Hz，与示例程序界面显示的根本不一样。在固定质量模式，采样频率、采样位宽和数据类型是我们上面
    ConstantQualityEncoding 模式下录音编码质量表格列举的数值，手动设置采样频率是无效的。<br>
    <br>
    然后我们测试固定比特率模式：<br>
    <center> <img src="images/ch03/ch03-03-03.png" alt="set2"> <img src="images/ch03/ch03-03-04.png"
        alt="rec2"> </center>
    我们设置固定比特率 32 kbps、采样频率 8000 Hz，然后开始录音。<br>
    在得到的录音文件中，这次采样频率是对的，为 8000 Hz，但是比特率却是 128 kbps，与设置的 32kbps 完全不一样。<br>
    固定比特率模式设置的比特率压根不对，差了好几倍。<br>
    这是 Qt 官方提供的示例，设置的编码器参数与实际得到录音文件参数总有不一致的情况出现。<br>
    <br>
    我们实际运用 QAudioRecorder 和 QAudioEncoderSettings 时，建议统一用固定质量模式
    ConstantQualityEncoding ，这个模式的采样参数是可以通过设置录音编码质量来确定，具体参数可以查询上面
    ConstantQualityEncoding 模式下录音编码质量表格。<br>
    <br>
    <div class="os2">3.3.2 QAudioProbe音频探针和 QAudioBuffer音频缓存</div>
    <br>
    QAudioRecorder 本身不会直接提供从声卡设备采集的音频数据，但是可以通过 QAudioProbe
    音频探针实时获取从声卡采集的音频数据。QAudioProbe 的函数非常简单，列举如下：<br>
    <div class="code">QAudioProbe(QObject * parent = 0) //构造函数<br>
      ~QAudioProbe()&nbsp; //析构函数<br>
      bool&nbsp; isActive() const&nbsp; //判断是否处于活跃状态，即是否在获取音频数据<br>
      bool&nbsp; setSource(QMediaObject * source)&nbsp;&nbsp; //设置数据源<br>
      bool&nbsp; setSource(QMediaRecorder * mediaRecorder) //设置数据源为录制对象</div>
    音频探针最关键的函数就是设置数据源，第一个 setSource() 以多媒体对象指针为参数，可以从音频解码器QAudioDecoder、摄像头
    QCamera、播放器 QMediaPlayer 和收音机 QRadioTuner 等对象获取实时的音频数据。<br>
    第二个 setSource() 以录制对象指针为参数，可以从多媒体录制对象 QMediaRecorder 和 录音对象 QAudioRecorder
    获取实时的音频数据。<br>
    无论是录音、录像还是播放器播放，都可以用 QAudioRecorder 探针实时获取音频数据。<br>
    QAudioRecorder 设置数据源的对象指针后，就会通过下面的信号实时提供音频数据：<br>
    <div class="code">void&nbsp; audioBufferProbed(const QAudioBuffer &amp;
      buffer)</div>
    参数里的 buffer 就是实时的音频缓存，操作该对象就可以获取实时数据。QAudioRecorder 探针使用举例如下：<br>
    <div class="code">QAudioRecorder *recorder = new QAudioRecorder();<br>
      QAudioProbe *probe = new QAudioProbe;<br>
      //配置编码器等等……<br>
      //关联信号，获取实时数据<br>
      connect(probe, SIGNAL(audioBufferProbed(QAudioBuffer)), this,
      SLOT(processBuffer(QAudioBuffer)));<br>
      //设置数据源<br>
      probe-&gt;setSource(recorder);<br>
      //开始录音<br>
      recorder-&gt;record(); //音频数据会周期地传递给槽函数 processBuffer(QAudioBuffer)</div>
    <br>
    QAudioRecorder还有下面的信号，通知释放所有音频缓存：
    <div class="code">void flush()</div>
    flush() 信号触发后，说明探针需要释放所有的音频缓存，程序必须立刻停止操作 QAudioBuffer 的内容，释放所有显式的音频缓存引用。<br>
    <br>
    QAudioBuffer 是带采样格式的音频缓存，获取音频采样格式使用下面函数：<br>
    <div class="code">QAudioFormat QAudioBuffer::​format() const</div>
    QAudioFormat 对象内容参考 3.1.2 节，包括音频的采样频率、通道数、采样位宽、采样点数据类型、字节序和编码格式。<br>
    如果需要判断音频缓存内是否有可用数据，使用下面函数：<br>
    <div class="code">bool QAudioBuffer::​isValid() const //采样帧数大于0就返回
      true，没数据就是false</div>
    获取音频缓存中采样帧数、总样本点数使用下面两个函数：<br>
    <div class="code">int QAudioBuffer::​frameCount() const //缓存中采样帧数<br>
      int QAudioBuffer::​sampleCount() const&nbsp; //缓存中总样本点数 = ​frameCount() *
      声道数</div>
    不论几个声道，所有声道的同一时刻采样点统称为一帧（frame），帧数也就等于一个声道内的采样点数。而总采样点数就是帧数 *
    声道数，统计所有声道的采样点数量。<br>
    获取缓存中数据片段对应的时间长度，使用下面函数：<br>
    <div class="code">qint64 QAudioBuffer::​duration() const&nbsp; //时间片长度，单位微秒</div>
    duration() 时间长度的单位是微秒（microseconds），时长的计算公式如下：<br>
    duration = frameCount / 采样频率<br>
    帧数与通道数量无关，因此帧数除以采样频率总是等于采样时长。<br>
    获取缓存中数据字节数的函数如下：<br>
    <div class="code">int QAudioBuffer::​byteCount() const</div>
    采样的字节数等于 ​sampleCount * 采样位宽 / 8 。<br>
    获取采样数据缓冲区的指针，使用下面函数：<br>
    <div class="code">const T * constData() const //只读缓冲区指针<br>
      const T * data() const //只读缓冲区指针<br>
      T * data() //读写缓冲区指针</div>
    T 是通过采样位宽和采样点数据类型联合确定的，典型的有下面五种：<br>
    <br>
    <table class="tabel">
      <tbody>
        <tr class="d1">
          <td style="width: 200px;" align="center"><b>缓冲区数据类型</b></td>
          <td style="width: 200px;" align="center"><b>采样位宽和类型</b></td>
          <td align="center"><b> 描述</b></td>
        </tr>
        <tr>
          <td>QAudioBuffer::​S8S</td>
          <td> 8bit&nbsp;SignedInt</td>
          <td> 8位有符号整数。 </td>
        </tr>
        <tr class="d1">
          <td><b>QAudioBuffer::​S8U</b></td>
          <td> 8bit UnSignedInt<br>
          </td>
          <td> 8位无符号整数。 </td>
        </tr>
        <tr>
          <td><b>QAudioBuffer::​S16S</b></td>
          <td> 16bit SignedInt</td>
          <td> 16位有符号整数。 </td>
        </tr>
        <tr class="d1">
          <td>QAudioBuffer::​S16U</td>
          <td>16bit UnSignedInt</td>
          <td> 16位无符号整数。 </td>
        </tr>
        <tr>
          <td>QAudioBuffer::​S32F</td>
          <td> 32bit Float</td>
          <td> 32位浮点数。 </td>
        </tr>
      </tbody>
    </table>
    <br>
    最常用的是8位无符号整数和16位有符号整数。constData() 和 data() 是模板函数，用法示范如下：<br>
    <div class="code">const qint16 *cdata =
      buffer-&gt;constData&lt;qint16&gt;(); //只读缓冲区指针<br>
      qint16 *data = buffer-&gt;data&lt;qint16&gt;();&nbsp; //读写缓冲区指针</div>
    qint16 就是 QAudioBuffer::​S16S ，使用 qint16 类型更简便。<br>
    <br>
    QAudioBuffer 的数据如果处于一个连续播放的音频流里面，获取该缓冲区数据在音频流中起始时间的函数如下：<br>
    <div class="code">qint64 QAudioBuffer::​startTime() const</div>
    如果缓存数据不是音频流中的数据片段，那么返回值是 -1。<br>
    <br>
    <div class="os2">3.3.3 QAudioRecorder录音示例 </div>
    <br>
    本小节示例采用 QAudioRecorder 进行录音，然后利用 QAudioProbe
    实时获取音频数据，并将音频数据发送到网络。通过本示例可以很容易实现网络语音聊天功能，并能自动录音为 wav 文件。<br>
    下面我们打开 QtCreator，新建一个 Qt Widgets Application 项目，在新建项目的向导里填写：<br>
    ①项目名称 <b>arecorder</b>，创建路径 E:\examples\ch03，点击下一步；<br>
    ②套件选择里面选择全部套件，点击下一步；<br>
    ③类信息界面先选择基类为 QWidget，修改类名为 <b>WidgetARecorder</b>，点击下一步；<br>
    ④项目管理不修改，点击完成。<br>
    我们先打开 arecorder.pro 文件，为项目添加 Qt 多媒体模块和网络模块，在 “QT += ” 一行末尾添加 ：<br>
    <div class="code">#-------------------------------------------------<br>
      #<br>
      # Project created by QtCreator 2018-11-19T10:00:33<br>
      #<br>
      #-------------------------------------------------<br>
      <br>
      QT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; += core gui <b>multimedia network</b><br>
      <br>
      greaterThan(QT_MAJOR_VERSION, 4): QT += widgets<br>
      <br>
      TARGET = arecorder<br>
      TEMPLATE = app<br>
      <br>
      <br>
      SOURCES += main.cpp\<br>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; widgetarecorder.cpp<br>
      <br>
      HEADERS&nbsp; += widgetarecorder.h<br>
      <br>
      FORMS&nbsp;&nbsp;&nbsp; += widgetarecorder.ui</div>
    编辑好后保存该文件并关闭。<br>
    我们打开 widgetarecorder.ui 界面文件，按照下图拖入控件：<br>
    <center> <img src="images/ch03/ch03-03-05.png" alt="ui" width="800"> </center>
    第一行是标签“声音输入设备”、组合框 comboBoxDeviceIn；<br>
    第二行是标签“音频编码器”、组合框 comboBoxCodec；<br>
    第三行是标签“编码质量”、组合框 comboBoxQuality；<br>
    第四行是标签“通道数量”、组合框 comboBoxChannelCount；<br>
    第五行是标签“容器格式”、组合框 comboBoxContainerFormat；<br>
    第六行是标签“文件路径”、单行编辑器 lineEditFile 。<br>
    前面六行控件使用一个栅格布局器布局。<br>
    第七行是标签“目标IP”、单行编辑器 lineEditIP、标签“目标端口”、单行编辑器 lineEditPort，第七行使用水平布局器排布。<br>
    第八行是“开始”按钮 pushButtonStart、“停止”按钮 pushButtonStop，第八行使用水平布局器排布。<br>
    第九行是标签“状态显示”，标签对象名修改为 labelStatus 。<br>
    窗口整体使用 垂直布局器排布，窗口大小 340 * 260 。<br>
    <br>
    窗口布局完成后，我们依次右击两个按钮，为“开始”按钮和“停止”按钮添加槽函数：<br>
    <center> <img src="images/slots/buttonclicked.png" alt="slot"> </center>
    添加两个按钮的槽函数后，我们保存界面文件，关闭界面文件，开始代码的编辑。<br>
    首先编辑头文件 widgetarecorder.h 的内容：<br>
    <div class="code"><span style=" color:#000080;">#ifndef</span><span style=" color:#c0c0c0;">
      </span>WIDGETARECORDER_H
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#define</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">WIDGETARECORDER_H</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QWidget&gt;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QAudioRecorder&gt;//录音</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QAudioEncoderSettings&gt;//音频编码器</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QAudioBuffer&gt;//音频缓存</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QAudioProbe&gt;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">//音频探针</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QUdpSocket&gt;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">//UDP套接字</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QHostAddress&gt;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">//主机地址</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QUrl&gt;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">//文件地址</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">namespace</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">Ui</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">{</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">class</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">WidgetARecorder</span><span style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">class</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">WidgetARecorder</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">:</span><span style=" color:#c0c0c0;"> </span><span style=" color:#808000;">public</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QWidget</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">Q_OBJECT</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">public</span><span style=" color:#000000;">:</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">explicit</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">WidgetARecorder</span><span
style=" color:#000000;">(</span><span style=" color:#800080;">QWidget</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span>parent<span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">0</span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">~</span><span style=" font-style:italic; color:#000000;">WidgetARecorder</span><span
style=" color:#000000;">();</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">private</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#808000;">slots</span><span style=" color:#000000;">:</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">on_pushButtonStart_clicked</span><span
style=" color:#000000;">();</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">on_pushButtonStop_clicked</span><span
style=" color:#000000;">();</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//手动添加槽函数</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//用户异步状态监测，反映录音对象的实际工作状态</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">onStatusChanged</span><span
style=" color:#000000;">(</span><span style=" color:#800080;">QMediaRecorder</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">Status</span><span
style=" color:#c0c0c0;"> </span>status<span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//出错信息监测</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">onError</span><span
style=" color:#000000;">(</span><span style=" color:#800080;">QMediaRecorder</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">Error</span><span
style=" color:#c0c0c0;"> </span>error<span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//录音时长监测，单位毫秒</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">onDurationChanged</span><span
style=" color:#000000;">(</span><span style=" color:#800080;">qint64</span><span
style=" color:#c0c0c0;"> </span>duration<span style=" color:#000000;">);</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//实时获取音频数据并发送到网络</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">onAudioBufferProbed</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">const</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QAudioBuffer</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&amp;</span><span
style=" color:#c0c0c0;"> </span>buffer<span style=" color:#000000;">);</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">private</span><span style=" color:#000000;">:</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">Ui</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">WidgetARecorder</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//录音对象</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QAudioRecorder</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">m_aRecorder</span><span
style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//编码器对象</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QAudioEncoderSettings</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">m_aEncoder</span><span
style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//音频探针对象</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QAudioProbe</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">m_aProbe</span><span
style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//套接字指针</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QUdpSocket</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span><span style=" color:#800000;">m_pSocket</span><span
style=" color:#000000;">;</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//界面初始化函数</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">InitUI</span><span
style=" color:#000000;">();</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//录音时禁止修改参数</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">holdParas</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">bool</span><span style=" color:#c0c0c0;"> </span>bHold<span
style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">};</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#endif</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">//</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">WIDGETARECORDER_H</span></pre>
</div>
    该文件添加了录音、音频编码器、音频缓存、音频探针、UDP套接字、主机地址、URL等类的头文件引用。<br>在窗口类声明中，头两个槽函数是通过按钮右键菜单添加的；<br>后面四个槽函数是手动编写的，手动添加的槽函数用于录音对象的异步状态监测、错误信息监测、录音时长监测以及获取音频探针实时采集的音频数据。<br><br>成员变量添加了录音对象、音频编码器对象、音频探针对象、套接字指针；<br>私有函数添加了初始化界面的函数和在录音时禁用参数控件的函数。<br>
<br>接下来我们分段编辑源代码文件 widgetarecorder.cpp ，首先是头文件包含、构造函数和析构函数：<br>
 <div class="code">
<style type="text/css">
p, li { white-space: pre-wrap; }
</style>

<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">"widgetarecorder.h"</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">"ui_widgetarecorder.h"</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QDebug&gt;//打印调试信息</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QMessageBox&gt;//消息框</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QIntValidator&gt;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">//限定端口号范围</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#800080;">WidgetARecorder</span><span style=" color:#000000;">::</span><span
style=" color:#000000;">WidgetARecorder</span><span style=" color:#000000;">(</span><span
style=" color:#800080;">QWidget</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">*</span><span style=" color:#000000;">parent</span><span
style=" color:#000000;">)</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">:</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QWidget</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">parent</span><span
style=" color:#000000;">),</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">new</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">Ui</span><span style=" color:#000000;">::</span><span style=" color:#800080;">WidgetARecorder</span><span
style=" color:#000000;">)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setupUi</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//指针初始化为空</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">m_pSocket</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">NULL</span><span style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//初始化界面</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">InitUI</span><span
style=" color:#000000;">();</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#800080;">WidgetARecorder</span><span style=" color:#000000;">::~</span><span
style=" font-style:italic; color:#000000;">WidgetARecorder</span><span style=" color:#000000;">()</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//指针置空</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">delete</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">m_pSocket</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;">   </span><span style=" color:#800000;">m_pSocket</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">NULL</span><span style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//销毁界面</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">delete</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">ui</span><span style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre></div>    
          
          
该文件添加了调试信息类、消息框类和整数验证器类的头文件包含；<br>构造函数将套接字指针 m_pSocket 初始化为空，然后调用初始化界面的函数 InitUI()。<br>析构函数里增加一行代码，删除了套接字对象，并将指针置空，其他成员变量会自动销毁。<br><br>
接下来编辑初始化界面函数，为各个输入控件添加内容：<br>
<div class="code">
<style type="text/css">
p, li { white-space: pre-wrap; }
</style>

<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#008000;">//初始化界面</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">void</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">WidgetARecorder</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">InitUI</span><span
style=" color:#000000;">()</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//填充输入设备组合框</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QStringList</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">listDevices</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">m_aRecorder</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">audioInputs</span><span style=" color:#000000;">();</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">comboBoxDeviceIn</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">addItems</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">listDevices</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//填充音频编码器组合框</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QStringList</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">listCodecs</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">m_aRecorder</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">supportedAudioCodecs</span><span style=" color:#000000;">();</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">comboBoxCodec</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">addItems</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">listCodecs</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">comboBoxCodec</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setCurrentText</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">"audio/pcm"</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">//默认PCM</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//编码质量</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QStringList</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">listQualities</span><span
style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//质量字符串的序号就是质量的枚举数值</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">listQualities</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#008000;">"VeryLow_8k8bit"</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#008000;">"Low_22k8bit"</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#008000;">"Normal_44k16bit"</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">                 </span><span style=" color:#000000;">&lt;&lt;</span><span
style=" color:#008000;">"High_48k16bit"</span><span style=" color:#000000;">&lt;&lt;</span><span
style=" color:#008000;">"VeryHigh_96k16bit"</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">comboBoxQuality</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">addItems</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">listQualities</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//通道数量</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QStringList</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">listChannels</span><span
style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">listChannels</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">"1"</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&lt;&lt;</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">"2"</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">comboBoxChannelCount</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">addItems</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">listChannels</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//容器格式</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QStringList</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">listContainers</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">m_aRecorder</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">supportedContainers</span><span style=" color:#000000;">();</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">comboBoxContainerFormat</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">addItems</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">listContainers</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">comboBoxContainerFormat</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setCurrentText</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">"audio/x-wav"</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">//默认WAV</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//默认文件路径</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">lineEditFile</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setText</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">"E:/ar_8k1c8bit.wav"</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//默认发送IP</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">lineEditIP</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setText</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">"127.0.0.1"</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//端口</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QIntValidator</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span><span style=" color:#000000;">vali</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#808000;">new</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QIntValidator</span><span
style=" color:#000000;">(</span><span style=" color:#000080;">1</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000080;">65535</span><span
style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">lineEditPort</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setValidator</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">vali</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">lineEditPort</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setText</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">"12345"</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span><span style=" color:#008000;">//默认端口</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//设置采集探针的数据源</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">m_aProbe</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">setSource</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&amp;</span><span
style=" color:#800000;">m_aRecorder</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//关联信号和槽函数</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">connect</span><span
style=" color:#000000;">(&amp;</span><span style=" color:#800000;">m_aRecorder</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#808000;">SIGNAL</span><span
style=" color:#000000;">(</span>statusChanged<span style=" color:#000000;">(</span><span
style=" color:#800080;">QMediaRecorder</span><span style=" color:#000000;">::</span><span
style=" color:#800080;">Status</span><span style=" color:#000000;">)),</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">            </span><span style=" color:#808000;">this</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#808000;">SLOT</span><span
style=" color:#000000;">(</span>onStatusChanged<span style=" color:#000000;">(</span><span
style=" color:#800080;">QMediaRecorder</span><span style=" color:#000000;">::</span><span
style=" color:#800080;">Status</span><span style=" color:#000000;">))</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">connect</span><span
style=" color:#000000;">(&amp;</span><span style=" color:#800000;">m_aRecorder</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#808000;">SIGNAL</span><span
style=" color:#000000;">(</span>error<span style=" color:#000000;">(</span><span
style=" color:#800080;">QMediaRecorder</span><span style=" color:#000000;">::</span><span
style=" color:#800080;">Error</span><span style=" color:#000000;">)),</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">            </span><span style=" color:#808000;">this</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#808000;">SLOT</span><span
style=" color:#000000;">(</span>onError<span style=" color:#000000;">(</span><span
style=" color:#800080;">QMediaRecorder</span><span style=" color:#000000;">::</span><span
style=" color:#800080;">Error</span><span style=" color:#000000;">))</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">connect</span><span
style=" color:#000000;">(&amp;</span><span style=" color:#800000;">m_aRecorder</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#808000;">SIGNAL</span><span
style=" color:#000000;">(</span>durationChanged<span style=" color:#000000;">(</span><span
style=" color:#800080;">qint64</span><span style=" color:#000000;">)),</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">            </span><span style=" color:#808000;">this</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#808000;">SLOT</span><span
style=" color:#000000;">(</span>onDurationChanged<span style=" color:#000000;">(</span><span
style=" color:#800080;">qint64</span><span style=" color:#000000;">))</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//实时获取数据的信号和槽</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">connect</span><span
style=" color:#000000;">(&amp;</span><span style=" color:#800000;">m_aProbe</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#808000;">SIGNAL</span><span
style=" color:#000000;">(</span>audioBufferProbed<span style=" color:#000000;">(</span><span
style=" color:#800080;">QAudioBuffer</span><span style=" color:#000000;">)),</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">            </span><span style=" color:#808000;">this</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#808000;">SLOT</span><span
style=" color:#000000;">(</span>onAudioBufferProbed<span style=" color:#000000;">(</span><span
style=" color:#800080;">QAudioBuffer</span><span style=" color:#000000;">))</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre></div> 
          
          
          
          该函数枚举音频输入设备字符串的列表，填充到组合框 comboBoxDeviceIn ；<br>枚举支持的音频编码器字符串列表，填充到组合框 comboBoxCodec，并设置默认编码器为 "audio/pcm" ；<br>手动填充了编码质量字符串列表，字符串的序号就是质量对应的枚举类型数值，质量字符串列表填充到 组合框comboBoxQuality ；<br>将单声道和双声道的字符串列表填充到组合框 comboBoxChannelCount；<br>获取录音对象支持的容器格式列表，填充到组合框 comboBoxContainerFormat，并设置默认为 "audio/x-wav" 格式；<br>设置默认文件路径为 "E:/ar_8k1c8bit.wav" ；<br>设置默认目标 IP 为 "127.0.0.1" ；<br>使用整数验证器限定端口编辑框内容为 1 到 65535，然后设置默认端口字符串 "12345" 。<br>设置音频探针采集的数据源为 m_aRecorder ；<br>关联录音对象的 异步状态信号、出错信号和录音时长变化信号到相应的槽函数；<br>最后关联音频探针的数据提供信号到对应的槽函数。<br>我们这个示例固定用 QMultimedia::ConstantQualityEncoding 固定质量模式录音，总是保存采集的 PCM 原始数据到指定的 wav 文件中。<br>
          <br>下面编辑“开始”按钮的槽函数：<br>
<div class="code">
<style type="text/css">
p, li { white-space: pre-wrap; }
</style>

<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">void</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">WidgetARecorder</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">on_pushButtonStart_clicked</span><span
style=" color:#000000;">()</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//网络参数设置</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QHostAddress</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">ipAddr</span><span
style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">!</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">ipAddr</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">setAddress</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">lineEditIP</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">text</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QMessageBox</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">warning</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"IP地址"</span><span style=" color:#000000;">),</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"IP地址格式不正确！"</span><span style=" color:#000000;">));</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//端口</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">quint16</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nPort</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">ui</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#800000;">lineEditPort</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#000000;">text</span><span style=" color:#000000;">().</span><span
style=" color:#000000;">toUShort</span><span style=" color:#000000;">();</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//套接字</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">m_pSocket</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#808000;">new</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QUdpSocket</span><span
style=" color:#000000;">();</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//连接到目标主机</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">m_pSocket</span><span
style=" color:#000000;">-&gt;</span><span style=" font-style:italic; color:#000000;">connectToHost</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">ipAddr</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nPort</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//设置录音参数</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//输入设备</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">m_aRecorder</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">setAudioInput</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">comboBoxDeviceIn</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">currentText</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//编码器参数</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">m_aEncoder</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">setCodec</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">comboBoxCodec</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">currentText</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//通道数</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">m_aEncoder</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">setChannelCount</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">comboBoxChannelCount</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">currentText</span><span
style=" color:#000000;">().</span><span style=" color:#000000;">toInt</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//固定质量模式</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">m_aEncoder</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">setEncodingMode</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QMultimedia</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">ConstantQualityEncoding</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//编码质量</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QMultimedia</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">EncodingQuality</span><span
style=" color:#c0c0c0;">  </span><span style=" color:#000000;">quality</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">(</span><span style=" color:#800080;">QMultimedia</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">EncodingQuality</span><span
style=" color:#000000;">)(</span><span style=" color:#800000;">ui</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#800000;">comboBoxQuality</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#000000;">currentIndex</span><span style=" color:#000000;">());</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">m_aEncoder</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">setQuality</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">quality</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//将编码器设置给录音对象</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">m_aRecorder</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">setAudioSettings</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800000;">m_aEncoder</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//文件容器格式</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">m_aRecorder</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">setContainerFormat</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">comboBoxContainerFormat</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">currentText</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//保存文件路径</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">m_aRecorder</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">setOutputLocation</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QUrl</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">fromLocalFile</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">lineEditFile</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">text</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//录音对象设置完毕，探针的数据源在初始化函数已经设置好了</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//开始录音</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">m_aRecorder</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">record</span><span
style=" color:#000000;">();</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//开始录音之后，打印保存文件URL</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span><span style=" color:#800000;">m_aRecorder</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">outputLocation</span><span
style=" color:#000000;">();</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//固定参数</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">holdParas</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">true</span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre></div>
        
          
          
          该函数首先尝试将IP地址字符串转为 QHostAddress 地址对象，如果转换失败就弹出消息框提示 IP 地址格式不正确，如果 IP 字符串转换正确，继续后面代码。<br>获取目标端口号，然后新建 UDP 套接字对象，调用套接字的连接目标 IP 和端口的函数，UDP 本身是无连接的，connectToHost() 函数仅仅是设置要发送的目标地址和端口，并不会真的连接到目标主机。<br>然后设置录音的参数：<br>设置选中的音频输入设备字符串；<br>设置选中的编码器字符串；<br>设置选择的采样通道数；<br>设置编码模式为 QMultimedia::ConstantQualityEncoding ；<br>将质量组合框的选中序号转为质量类型，然后设置给编码器；<br>接着将编码器对象设置给录音对象；<br>为录音对象设置文件容器格式；<br>设置录音保存的文件 URL ；<br>设置参数完成后，调用 m_aRecorder.record() 进行录音；<br>开始录音之后就可以打印保存文件的 URL；<br>最后调用 holdParas(true) 禁用界面的输入控件和“开始”按钮。<br>
          <br>录音时禁用控件，停止录音后恢复控件的函数如下：<br>
<div class="code">
<style type="text/css">
p, li { white-space: pre-wrap; }
</style>

<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#008000;">//录音时固定参数</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">void</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">WidgetARecorder</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">holdParas</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">bool</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">bHold</span><span style=" color:#000000;">)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//五个组合框</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">comboBoxDeviceIn</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setDisabled</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">bHold</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">comboBoxCodec</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setDisabled</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">bHold</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">comboBoxQuality</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setDisabled</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">bHold</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">comboBoxChannelCount</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setDisabled</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">bHold</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">comboBoxContainerFormat</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setDisabled</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">bHold</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//三个编辑框</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">lineEditFile</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setDisabled</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">bHold</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">lineEditIP</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setDisabled</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">bHold</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">lineEditPort</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setDisabled</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">bHold</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//开始按钮</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">pushButtonStart</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setDisabled</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">bHold</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre></div>
          
          
          当参数 bHold 为 true 时，禁用五个组合框、三个编辑框和“开始”按钮；<br>当参数 bHold 为 false 时，重新启用上述按钮。<br>
          
          <br>接下来是两个非常简单的槽函数，用于监测异步状态和出错信息：<br>
<div class="code">
<style type="text/css">
p, li { white-space: pre-wrap; }
</style>

<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">void</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">WidgetARecorder</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">onStatusChanged</span><span
style=" color:#000000;">(</span><span style=" color:#800080;">QMediaRecorder</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">Status</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">status</span><span
style=" color:#000000;">)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span><span style=" color:#000000;">status</span><span
style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">void</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">WidgetARecorder</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">onError</span><span
style=" color:#000000;">(</span><span style=" color:#800080;">QMediaRecorder</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">Error</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">error</span><span
style=" color:#000000;">)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span><span style=" color:#000000;">error</span><span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#008000;">":</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">"</span><span style=" color:#000000;">&lt;&lt;</span><span
style=" color:#800000;">m_aRecorder</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">errorString</span><span style=" color:#000000;">();</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre></div>
          
          这两个槽函数比较简单，就是打印状态变量，打印出错变量和错误信息字符串。<br>
          <br>接下来编辑录音时长变化信号对应的槽函数：<br>
<div class="code">
<style type="text/css">
p, li { white-space: pre-wrap; }
</style>

<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">void</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">WidgetARecorder</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">onDurationChanged</span><span
style=" color:#000000;">(</span><span style=" color:#800080;">qint64</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">duration</span><span
style=" color:#000000;">)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">duration</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&lt;=</span><span
style=" color:#000080;">0</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">//时间不合法</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//秒数</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">和</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">毫秒数</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">qint64</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nSec</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">duration</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">/</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">1000</span><span style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">qint64</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nMS</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">duration</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">%</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">1000</span><span style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strStatus</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">tr</span><span style=" color:#000000;">(</span><span style=" color:#008000;">"录音时间</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">%1.%2</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">s"</span><span style=" color:#000000;">).</span><span
style=" color:#000000;">arg</span><span style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">nSec</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">).</span><span
style=" color:#000000;">arg</span><span style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">nMS</span><span style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">3</span><span style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">10</span><span style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">QChar</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">'0'</span><span style=" color:#000000;">));</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//显示到状态标签</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">labelStatus</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setText</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">strStatus</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre></div>    
          
          
          
          该函数先判断时长是否合法，不合法就不处理。<br>参数 duration 是录音时长总毫秒数，我们对其提取时长的秒数和毫秒余数，<br>构造字符串 strStatus ，显示到状态标签里面。<br>时长变化信号其实不是每个毫秒都触发，那样会导致过度频繁调用槽函数，浪费计算资源。<br>经过测试，实际情况下录音对象每秒钟只触发两次时长变化信号。<br>虽然参数 duration 单位是毫秒，实际是按照秒钟级别触发的。<br>
          <br>下面我们编辑探针实时采集数据信号的槽函数：<br>
<div class="code">
<style type="text/css">
p, li { white-space: pre-wrap; }
</style>

<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">void</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">WidgetARecorder</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">onAudioBufferProbed</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">const</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QAudioBuffer</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&amp;</span><span
style=" color:#000000;">buffer</span><span style=" color:#000000;">)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">int</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nByteCount</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">buffer</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">byteCount</span><span style=" color:#000000;">();</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">const</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#808000;">char</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">*</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">data</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">buffer</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">constData</span><span style=" color:#000000;">&lt;</span><span
style=" color:#808000;">char</span><span style=" color:#000000;">&gt;();</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//发送</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000080;">NULL</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">!=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">m_pSocket</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800000;">m_pSocket</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">write</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">data</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nByteCount</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre></div>
          
          
          
          该函数获取音频缓存中的字节总数 nByteCount ，获取数据指针存到 data ，因为后面网络发送用的是const char* 指针，所以我们获取数据是直接获取 const char * 数据指针。<br>判断套接字指针，如果非空就将数据发送到网络，之前“开始”按钮槽函数代码已经指定了目标地址和端口，所以这里发送时不需要提供目标地址和端口，直接调用 write() 即可。<br>
          <br>最后编辑“停止”按钮的槽函数代码：<br>
<div class="code">
<style type="text/css">
p, li { white-space: pre-wrap; }
</style>

<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">void</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">WidgetARecorder</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">on_pushButtonStop_clicked</span><span
style=" color:#000000;">()</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//如果没开始，不处理</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800000;">m_aRecorder</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">state</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">==</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QMediaRecorder</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">StoppedState</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//停止录音</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">m_aRecorder</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">stop</span><span style=" color:#000000;">();</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//套接字</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000080;">NULL</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">!=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">m_pSocket</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800000;">m_pSocket</span><span
style=" color:#000000;">-&gt;</span><span style=" font-style:italic; color:#000000;">close</span><span
style=" color:#000000;">();</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//删除网络套接字</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">delete</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">m_pSocket</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;">   </span><span style=" color:#800000;">m_pSocket</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">NULL</span><span style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
<pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//恢复控件</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">holdParas</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">false</span><span
style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#800000;">labelStatus</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setText</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">tr</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"状态显示"</span><span
style=" color:#000000;">)</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span><span
style=" color:#008000;">//还原状态标签</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre></div>
          
          
          该函数先判断录音对象的同步状态，如果是停止工作状态，那么没有录音，直接返回，不需要处理。<br>如果不是停止状态，那么需要进行停止操作，调用 m_aRecorder.stop() 停止录音；<br>如果套接字非空就关闭网络套接字，删除该对象，将指针置空；<br>最后恢复控件的可用状态，并将状态标签的文本改回初始文本 "状态显示" 。<br>&nbsp;<br>代码讲解到这，我们将耳麦或麦克风、音箱连接到电脑，先运行接收并播放网络数据的程序：<br>从开始菜单运行 Qt 命令行，
          将 3.2.3 一节的 playudp.exe 拖入到 Qt 命令行，并运行playudp.exe，点击“开始”：<br>
  <center> <img src="images/ch03/ch03-03-06.png" alt="run"> </center>

          
          
          接收端已经开始监听，我们构建并运行本小节的示例，点击“开始”按钮：<br>
  <center> <img src="images/ch03/ch03-03-07.png" alt="run"> </center>
          
          录音示例运行时，不仅将音频数据保存到了 E:/ar_8k1c8bit.wav 文件，还通过音频探针将采集的数据发送到网络，接收端程序可以清楚地看到接收了音频数据，并从声卡播放出来。我们对麦克风喊话，可以从耳机或音箱听到自己的喊话。这个示例讲解到这，本节使用录音类 QAudioRecorder 的好处是可以自动将音频数据保存为 wav 文件，比裸格式 pcm 文件更方便播放器播放。<br><br><br>
    <br>
    <table style="text-align: left; width: 100%;" border="0" cellpadding="2" cellspacing="2">
      <tbody>
        <tr>
          <td style="width: 40%;">
            <div style="text-align: center;"><a href="ch03-02.htm"><img class="pic"
style="width: 32px; height: 32px;" alt="prev" src="images/pics/prev.png"></a></div>
          </td>
          <td style="width: 20%;">
            <div style="text-align: center;"><a href="contents.htm"><img class="pic"
style="width: 32px; height: 32px;" alt="contents" src="images/pics/contents.png"></a></div>
          </td>
          <td style="width: 40%;">
            <div style="text-align: center;"><a href="ch03-04.htm"><img class="pic"
style="width: 32px; height: 32px;" alt="next" src="images/pics/next.png"></a></div>
          </td>
        </tr>
      </tbody>
    </table>
</body></html>